#!/bin/bash -e

#  Tool to create (and optionally install) Debian packages of i3-gaps.
#  Copyright (C) 2017  Gerhard A. Dittes
#
#  This program is free software: you can redistribute it and/or modify
#  it under the terms of the GNU General Public License as published by
#  the Free Software Foundation, either version 3 of the License, or
#  any later version.
#
#  This program is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#  GNU General Public License for more details.
#
#  You should have received a copy of the GNU General Public License
#  along with this program.  If not, see <http://www.gnu.org/licenses/>.

# Namespace: igd

# Variables

igd_BASEDIR="$(pwd)"
igd_GITDIR="${igd_BASEDIR}/i3-gaps"
igd_PATCHDIR="${igd_BASEDIR}/patches"
igd_GITURL="https://github.com/Airblader/i3.git"
igd_BRANCH_DEFAULT="gaps"
igd_BRANCH_ALTERNATIVE="gaps-next"
igd_BRANCH="${igd_BRANCH_DEFAULT}"
igd_TIMESTAMP="$(date +%Y%m%d%H%M%S)"

# Functions

igd_usage()
{
	printf "\nThis tool creates (and optionally installs) Debian packages of i3-gaps.\n\n"
	printf "Usage: ${0} [OPTION...]\n\n"
	printf "  -h, --help         show this help and quit\n"
	printf "      --config       print \"i3-gaps config\" recommendation\n"
}

igd_checkHelp()
{
	if [ ${#} -ge 1 ]; then
		case "${1}" in
		"-h"|"--help")
			igd_usage
			exit 0
			;;
		"--config")
			igd_printI3GapsConfig
			exit 0
			;;
		*)
			igd_usage
			exit 23
			;;
		esac
	fi
}

igd_handleLib()
{
	git submodule update --init --recursive
	. bash-lib/gad-lib.bash
	gad_LABEL="igd"
}

igd_startupHint()
{
	gad_readAndContinue "This tool creates (and optionally installs) Debian packages of i3-gaps..."
	gad_readAndContinue "This tool comes without any warranty and in the hope to be useful..."
}

igd_ensureI3ToBeInstalled()
{
	gad_log "Checking i3 installation..."

	if ! dpkg -s i3-wm &> /dev/null; then
		if gad_question "i3 window manager not found, install it using apt?" "y"; then
			sudo apt -y install i3-wm
			if gad_question "Install also i3 metapackage (recommended tools)?" "y"; then
				sudo apt -y install i3
			fi
		else
			exit 42
		fi
	fi
}

igd_checkSourcesList()
{
	gad_log "Checking sources.list(s) to contain sources (\"weak\")..."

	if ! grep --quiet -r "^ *deb-src.*\(\(debian\)\|\(ubuntu\)\|\(kali\)\|\(ascii\)\|\(beowulf\)\)[/ ].*main" /etc/apt/sources.list*; then
		gad_readAndContinue "Please add necessary \"deb-src\" line(s) to your apt sources (and run an 'apt update')."
		exit 1
	fi
}

igd_installBuildDeps()
{
	gad_readAndContinue "Installing (basic) build dependencies..."
	sudo apt -y build-dep i3-wm

	gad_readAndContinue "Installing (additional) build dependencies..."
	sudo apt -y install \
		devscripts dpkg-dev \
		dh-autoreconf \
		libxcb-xrm-dev \
		libxcb-xkb-dev \
		libxkbcommon-dev \
		libxkbcommon-x11-dev \
		libxcb-shape0-dev \
		meson
}

igd_ensureGitToBeInstalled()
{
	gad_log "Checking git installation..."

	if ! dpkg -s git &> /dev/null; then
		if gad_question "git not found, install it using apt?" "y"; then
			sudo apt -y install git
		else
			exit 44
		fi
	fi
}

igd_clone()
{
	if [ ! -d ${igd_GITDIR} ]; then
		gad_readAndContinue "Cloning i3 gaps into \"${igd_GITDIR}\"..."
		git clone ${igd_GITURL} ${igd_GITDIR}
	else
		gad_log "Skip cloning as ${igd_GITDIR} already exists."
	fi
}

igd_switchToGitDir()
{
	gad_log "Entering directory ${igd_GITDIR}..."
	cd ${igd_GITDIR}
}

igd_cleanUpGitStuff()
{
	gad_log "Cleaning up..."
	git reset --hard HEAD
	git clean -fdx
}

igd_prepareBranch()
{
	if ! gad_question "Use branch \"${igd_BRANCH_DEFAULT}\"? (\"${igd_BRANCH_ALTERNATIVE}\" otherwise)" "y"; then
		igd_BRANCH=${igd_BRANCH_ALTERNATIVE}
	fi

	git checkout ${igd_BRANCH}
	git pull --no-rebase
}

igd_updateDebianChangelog()
{
	gad_log "Updating Debian changelog..."

	local versionFoo="$(head -1 debian/changelog | cut -d'(' -f2 | cut -d'-' -f1 || echo "0.0.0")"
	local versionBar="$(grep -P -o "\d+(?:\.\d+)+" I3_VERSION 2> /dev/null || echo "0.0.0")"

	local version="${versionFoo}"
	if dpkg --compare-versions "${versionFoo}" lt "${versionBar}"; then version="${versionBar}"; fi

	local newVersion="${version}-1gerardo+${igd_TIMESTAMP}"
	gad_log "Version detected: \"${versionFoo}\" VS \"${versionBar}\" ~> \"${newVersion}\""

	DEBEMAIL="maestro.gerardo@gmail.com" DEBFULLNAME="Gerhard A. Dittes" \
		debchange --dist=unstable --newversion="${newVersion}" "New upstream."
}

igd_fixRules()
{
	gad_log "Disable sanitizers..."
	patch --forward -r - -p1 <${igd_PATCHDIR}/0001-debian-Disable-sanitizers.patch || gad_log "Already patched."

	gad_log "Fix rules file..."
	cat <<EOF >>debian/rules

override_dh_install:
override_dh_installdocs:
override_dh_installman:
	dh_install -O--parallel
EOF
}

igd_buildDebianPackages()
{
	gad_readAndContinue "Build Debian packages..."
	dpkg-buildpackage -us -uc
}

igd_switchToBaseDir()
{
	gad_log "Entering directory ${igd_BASEDIR}..."
	cd ${igd_BASEDIR}
}

igd_installDebianPackages()
{
	local debs=$(echo i3_*${igd_TIMESTAMP}*deb i3-wm_*${igd_TIMESTAMP}*deb)
	gad_log "Result: ${debs}"
	if gad_question "Install created Debian packages?" "y"; then
		sudo dpkg -i ${debs}
	fi
}

igd_cleanUp()
{
	if gad_question "Remove created files?" "y"; then
		rm -v *${igd_TIMESTAMP}*
	fi
}

igd_printI3GapsConfig()
{
	cat <<EOF

### i3-gaps stuff ###

# Necessary for i3-gaps to work properly (pixel can be any value)
for_window [class="^.*"] border pixel 3

# Smart Gaps
smart_gaps on

# Smart Borders
smart_borders on

# Set inner/outer gaps
gaps inner 14
gaps outer 0

# Gaps mode
set \$mode_gaps Gaps: (o)uter, (i)nner, (h)orizontal, (v)ertical, (t)op, (r)ight, (b)ottom, (l)eft
set \$mode_gaps_outer Outer Gaps: +|-|0 (local), Shift + +|-|0 (global)
set \$mode_gaps_inner Inner Gaps: +|-|0 (local), Shift + +|-|0 (global)
set \$mode_gaps_horiz Horizontal Gaps: +|-|0 (local), Shift + +|-|0 (global)
set \$mode_gaps_verti Vertical Gaps: +|-|0 (local), Shift + +|-|0 (global)
set \$mode_gaps_top Top Gaps: +|-|0 (local), Shift + +|-|0 (global)
set \$mode_gaps_right Right Gaps: +|-|0 (local), Shift + +|-|0 (global)
set \$mode_gaps_bottom Bottom Gaps: +|-|0 (local), Shift + +|-|0 (global)
set \$mode_gaps_left Left Gaps: +|-|0 (local), Shift + +|-|0 (global)
bindsym \$mod+Shift+g mode "\$mode_gaps"

mode "\$mode_gaps" {
        bindsym o      mode "\$mode_gaps_outer"
        bindsym i      mode "\$mode_gaps_inner"
        bindsym h      mode "\$mode_gaps_horiz"
        bindsym v      mode "\$mode_gaps_verti"
        bindsym t      mode "\$mode_gaps_top"
        bindsym r      mode "\$mode_gaps_right"
        bindsym b      mode "\$mode_gaps_bottom"
        bindsym l      mode "\$mode_gaps_left"
        bindsym Return mode "\$mode_gaps"
        bindsym Escape mode "default"
}

mode "\$mode_gaps_outer" {
        bindsym plus  gaps outer current plus 5
        bindsym minus gaps outer current minus 5
        bindsym 0     gaps outer current set 0

        bindsym Shift+plus  gaps outer all plus 5
        bindsym Shift+minus gaps outer all minus 5
        bindsym Shift+0     gaps outer all set 0

        bindsym Return mode "\$mode_gaps"
        bindsym Escape mode "default"
}
mode "\$mode_gaps_inner" {
        bindsym plus  gaps inner current plus 5
        bindsym minus gaps inner current minus 5
        bindsym 0     gaps inner current set 0

        bindsym Shift+plus  gaps inner all plus 5
        bindsym Shift+minus gaps inner all minus 5
        bindsym Shift+0     gaps inner all set 0

        bindsym Return mode "\$mode_gaps"
        bindsym Escape mode "default"
}
mode "\$mode_gaps_horiz" {
        bindsym plus  gaps horizontal current plus 5
        bindsym minus gaps horizontal current minus 5
        bindsym 0     gaps horizontal current set 0

        bindsym Shift+plus  gaps horizontal all plus 5
        bindsym Shift+minus gaps horizontal all minus 5
        bindsym Shift+0     gaps horizontal all set 0

        bindsym Return mode "\$mode_gaps"
        bindsym Escape mode "default"
}
mode "\$mode_gaps_verti" {
        bindsym plus  gaps vertical current plus 5
        bindsym minus gaps vertical current minus 5
        bindsym 0     gaps vertical current set 0

        bindsym Shift+plus  gaps vertical all plus 5
        bindsym Shift+minus gaps vertical all minus 5
        bindsym Shift+0     gaps vertical all set 0

        bindsym Return mode "\$mode_gaps"
        bindsym Escape mode "default"
}
mode "\$mode_gaps_top" {
        bindsym plus  gaps top current plus 5
        bindsym minus gaps top current minus 5
        bindsym 0     gaps top current set 0

        bindsym Shift+plus  gaps top all plus 5
        bindsym Shift+minus gaps top all minus 5
        bindsym Shift+0     gaps top all set 0

        bindsym Return mode "\$mode_gaps"
        bindsym Escape mode "default"
}
mode "\$mode_gaps_right" {
        bindsym plus  gaps right current plus 5
        bindsym minus gaps right current minus 5
        bindsym 0     gaps right current set 0

        bindsym Shift+plus  gaps right all plus 5
        bindsym Shift+minus gaps right all minus 5
        bindsym Shift+0     gaps right all set 0

        bindsym Return mode "\$mode_gaps"
        bindsym Escape mode "default"
}
mode "\$mode_gaps_bottom" {
        bindsym plus  gaps bottom current plus 5
        bindsym minus gaps bottom current minus 5
        bindsym 0     gaps bottom current set 0

        bindsym Shift+plus  gaps bottom all plus 5
        bindsym Shift+minus gaps bottom all minus 5
        bindsym Shift+0     gaps bottom all set 0

        bindsym Return mode "\$mode_gaps"
        bindsym Escape mode "default"
}
mode "\$mode_gaps_left" {
        bindsym plus  gaps left current plus 5
        bindsym minus gaps left current minus 5
        bindsym 0     gaps left current set 0

        bindsym Shift+plus  gaps left all plus 5
        bindsym Shift+minus gaps left all minus 5
        bindsym Shift+0     gaps left all set 0

        bindsym Return mode "\$mode_gaps"
        bindsym Escape mode "default"
}

EOF
}

igd_configHint()
{
	gad_readAndContinue "You might consider appending the following lines to your (existing) i3-config..."
	igd_printI3GapsConfig

	gad_readAndContinue "You can print them at any time later using \"${0} --config\"..."
}

igd_updatePotentialConfigs()
{
	local configs="${HOME}/.i3/config ${HOME}/.config/i3/config"

	for f in ${configs}; do
		if [ -w ${f} ] && gad_question "Or shall I do it for you now (file: ${f})?"; then
			igd_printI3GapsConfig >> ${f}
		fi
	done
}

igd_handleConfig()
{
	igd_configHint
	igd_updatePotentialConfigs
}

igd_byeBye()
{
	gad_log "Done! Now you should be prepared to (re)start i3..."
}

main()
{
	igd_checkHelp ${@}
	igd_handleLib
	igd_startupHint
	igd_ensureI3ToBeInstalled
	igd_checkSourcesList
	igd_installBuildDeps
	igd_ensureGitToBeInstalled
	igd_clone
	igd_switchToGitDir
	igd_cleanUpGitStuff
	igd_prepareBranch
	igd_updateDebianChangelog
	igd_fixRules
	igd_buildDebianPackages
	igd_switchToBaseDir
	igd_installDebianPackages
	igd_handleConfig
	igd_cleanUp
	igd_byeBye
}

main ${@}
